/*
 * Project Beknyou
 * Copyright (c) 2010-2011 Saint Paul College, All Rights Reserved
 * Redistributions in source code form must reproduce the above
 * Copyright and this condition.
 * The contents of this file are subject to the GNU General Public
 * License, Version 2 (the "License"); you may not use this file
 * except in compliance with the License. A copy of the License is
 * available at http://www.opensource.org/licenses/gpl-license.php.
 */
package com.benkyou.client.appstates;

import com.benkyou.client.GameClient;
import com.benkyou.client.systems.DefaultCamSystem;
import com.benkyou.common.Player;
import com.benkyou.common.messages.PlayerMessage;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.Node;
import com.jme3.input.InputManager;
import com.jme3.math.Matrix3f;

/**
 *
 * @author Austin Allman, Adam Hess
 */
public class WorldPhysicsAppState extends AbstractAppState implements PhysicsCollisionListener {

    /**
     * For each Spatial that you want to be physical:
    Create a CollisionShape.
    Create a PhysicsControl by supplying the CollisionShape and mass.
    E.g. com.jme3.bullet.control.RigidBodyControl
    Add the PhysicsControl to the Spatial.
    Add the PhysicsControl to the physicsSpace object.
    Attach the Spatial to the rootNode, as usual.
    (Optional) Implement the PhysicsCollisionListener interface to respond to PhysicsCollisionEvents if desired
     */
    private BulletAppState bulletAppState;
    private PhysicsSpace physicsSpace;
    private AppStateManager stateManager;
    private Node moveTo;
    private DefaultCamSystem camSys;
    private Geometry mark;
    private Node rootNode;
    private InputManager inputManager;
    private Vector3f walkDirection;
    private Spatial terrain;
    private Node root;
    private GameClient gameClient;
    private Vector3f messageDirection;
    private Vector3f avatarCurPos = new Vector3f();

    /**
     * 
     * @param gameClient
     */
    public WorldPhysicsAppState(GameClient gameClient) {
        this.gameClient = gameClient;
        terrain = gameClient.getTerrainSystem().getTerrain();

        stateManager = gameClient.getStateManager();
        camSys = gameClient.getCamSys();
        root = gameClient.getRoot();
        bulletAppState = new BulletAppState();
  
        walkDirection = new Vector3f();
        messageDirection = new Vector3f();
        messageDirection.set(0f, 0f, 0f);
        stateManager.attach(bulletAppState);
        //Sets up the physics space for this bulletappstate
        physicsSpace = bulletAppState.getPhysicsSpace();
        physicsSpace.setGravity(new Vector3f(0f, -12f, 0f));
        physicsSpace.setAccuracy(0.005f);
        //gives the world floor colision with 0 gravity so it doesent fall
        
        root.addControl(new RigidBodyControl(0.0f));
        //attaches the world floor to the bulletAppState
        physicsSpace.add(root);


    }

    /**
     * 
     */
    public void setupAllPlayers() {
        for (Player p : gameClient.getPlayerList()) {
            if(!p.isPhysicsSetup()){
            physicsSpace.add(p.setupCharacterPhysics().getCharacterPhysics());
            gameClient.getRootNode().attachChild(p);
            p.setPhysicsSetup(true);
            }
        }
    }

    /**
     * 
     * @return
     */
    public PhysicsSpace getPhysicsSpace() {
        return physicsSpace;
    }

    @Override
    public void update(float tpf) {
        if (gameClient.isUp()) {
            for (Player p : gameClient.getPlayerList()) {
      
                if (p.getAvatarControlSystem().isUpdateNeeded()) {
                    if (p.getAvatarControlSystem().isMainPlayer()) {
                        moveMainPlayer(p, tpf);
                    } else {
                        if(p.getCharacterPhysics() != null && p.getCurrentPosition() != null){
                        p.getCharacterPhysics().setPhysicsLocation(p.getCurrentPosition());
                       p.getAvatarControlSystem().moveCharacter(p.getWalkDirection(), tpf);
                      // p.getAvatar().setLocalTranslation(p.getCurrentPosition());
                        }
                   
                    }
                    p.getAvatarControlSystem().setUpdateNeeded(false);
                    
                }

            }

           
        }
    }

    /**
     * 
     * @param pce
     */
    public void collision(PhysicsCollisionEvent pce) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private void moveMainPlayer(Player p, float tpf) {
        Vector3f camDir = null;
        Vector3f camLeft = null;
        if (p.getAvatarControlSystem().isRun()) {
            camDir = camSys.getDirection().normalizeLocal().mult(5f);
            camLeft = camSys.getCamLeft().normalizeLocal().mult(5f);
        } else {
            camDir = camSys.getDirection().clone().multLocal(0.05f);
            camLeft = camSys.getCamLeft().clone().multLocal(0.15f);

        }
        camDir.y = 0;
        camLeft.y = 0;

        walkDirection.set(0f, 0f, 0f);
        if (p.getAvatarControlSystem().isLeft()) {

            walkDirection.addLocal(camLeft);
        }
        if (p.getAvatarControlSystem().isRight()) {
            walkDirection.addLocal(camLeft.negate());
        }
        if (p.getAvatarControlSystem().isUp()) {
            walkDirection.addLocal(camDir);
        }
        if (p.getAvatarControlSystem().isDown()) {
            walkDirection.addLocal(camDir.negate());
        } else {
        }
        if (walkDirection.getX() != messageDirection.getX() && walkDirection.getZ() != messageDirection.getZ()) {
            messageDirection = walkDirection.clone();
            
            p.getCharacterPhysics().getPhysicsLocation(avatarCurPos);
            gameClient.getMyClient().send(new PlayerMessage(p.getName(), true, "Walk",messageDirection.getX(), messageDirection.getY(), messageDirection.getZ(), avatarCurPos.getX(), avatarCurPos.getY(), avatarCurPos.getZ()));
           
        }
        p.getAvatarControlSystem().moveCharacter(walkDirection, tpf);
  

    }

}
